#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import os, io, json, subprocess, tempfile
from urllib import parse
from wsgiref.simple_server import make_server
import time
import psutil

# EXEC = sys.executable
EXEC = '/usr/bin/python'
PORT = 39093
HOST = ['localhost:%d' % PORT,'127.0.0.1:%d' % PORT,'run.chenzhibin.vip:%d' % PORT,'local.chenzhibin.vip:%d' % PORT,'chenzhibin.vip:%d' % PORT,'www.chenzhibin.vip:%d' % PORT,'dnshe.cn:%d' % PORT,'88cto.cn:%d' % PORT,'localhost','127.0.0.1','run.chenzhibin.vip','local.chenzhibin.vip','chenzhibin.vip','www.chenzhibin.vip','dnshe.cn','88cto.cn']
# TEMP = tempfile.mkdtemp(suffix='_py', prefix='learn_python_')
INDEX = 0


def get_name():
    global INDEX
    INDEX = INDEX + 1
    return 'test_%d' % INDEX

def write_py(name, code):
    # 每次py运行都生成不同的临时文件夹，貌似没有name也是不同的，确保一下，还是加了name
    TEMP = tempfile.mkdtemp(suffix='_py', prefix='learn_python_%s'% name)
    fpath = os.path.join(TEMP, '%s.py' % name)
    with open(fpath, 'w', encoding='utf-8') as f:
        f.write(code)
    print('Code wrote to: %s' % fpath)
    return fpath

def decode(s):
    try:
        return s.decode('utf-8')
    except UnicodeDecodeError:
        return s.decode('gbk')

def show_info(self):
    #计算消耗内存
    pid = os.getpid()
    # 模块名比较容易理解：获得当前进程的pid
    p = psutil.Process(pid)
    # 根据pid找到进程，进而找到占用的内存值
    info = p.memory_full_info()
    memory = info.uss / 1024 
    return memory

def application(environ, start_response):
    host = environ.get('HTTP_HOST')
    method = environ.get('REQUEST_METHOD')
    path = environ.get('PATH_INFO')
    if method == 'GET' and path == '/':
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [b'<html><head><title>Learning Python</title></head><body><form method="post" action="/run"><textarea name="code" style="width:90%;height: 600px"></textarea><p><button type="submit">Run</button></p></form></body></html>']
    if method == 'GET' and path == '/env':
        start_response('200 OK', [('Content-Type', 'text/html')])
        L = [b'<html><head><title>ENV</title></head><body>']
        for k, v in environ.items():
            p = '<p>%s = %s' % (k, str(v))
            L.append(p.encode('utf-8'))
        L.append(b'</html>')
        return L
    # if host not in HOST or method != 'POST' or path != '/run' or not environ.get('CONTENT_TYPE', '').lower().startswith('application/x-www-form-urlencoded'):
    if host not in HOST or method != 'POST' or not environ.get('CONTENT_TYPE', '').lower().startswith('application/x-www-form-urlencoded'):
        start_response('400 Bad Request', [('Content-Type', 'application/json')])
        return [b'{"error":"bad_request"}']
    s = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
    qs = parse.parse_qs(s.decode('utf-8'))
    if not 'code' in qs:
        start_response('400 Bad Request', [('Content-Type', 'application/json')])
        return [b'{"error":"invalid_params"}']
    name = qs['name'][0] if 'name' in qs else get_name()
    code = qs['code'][0]
    headers = [('Content-Type', 'application/json')]
    origin = environ.get('HTTP_ORIGIN', '')
    if origin.find('localhost') == -1 and origin.find('chenzhibin.vip') == -1 and origin.find('127.0.0.1') == -1 and origin.find('dnshe.cn') == -1 and origin.find('88cto.cn') == -1:
        start_response('400 Bad Request', [('Content-Type', 'application/json')])
        return [b'{"error":"invalid_origin"}']
    headers.append(('Access-Control-Allow-Origin', origin))
    start_response('200 OK', headers)
    r = dict()
    try:
        fpath = write_py(name, code)
        print('Execute: %s %s' % (EXEC, fpath))
        # start = time.clock()  #Python 3.8 已移除 clock() 方法 可以使用 time.perf_counter() 或 time.process_time() 方法替代。
        # process_counter()适合小一点的程序测试，不会计算sleep()时间
        start = time.process_time()
        start_memory=show_info('开始')
        r['output'] = decode(subprocess.check_output([EXEC, fpath], stderr=subprocess.STDOUT, timeout=5))
        end = time.process_time()
        r['runtime'] = str((end-start)*1000)+' ms'
        end_memory=show_info('结束')
        r['memory'] = str(end_memory-start_memory)+' KB'
    except subprocess.CalledProcessError as e:
        r = dict(error='Exception', output=decode(e.output))
    except subprocess.TimeoutExpired as e:
        r = dict(error='Timeout', output='执行超时')
    except subprocess.CalledProcessError as e:
        r = dict(error='Error', output='执行错误')
    print('Execute done.')
    return [json.dumps(r).encode('utf-8')]

